package com.etop.weiway.wxmanage.service;

import com.etop.weiway.basic.service.BaseService;
import com.etop.weiway.wxmanage.dao.*;
import com.etop.weiway.wxmanage.entity.*;
import com.etop.weiway.wxmanage.util.WeixinTimeUtil;
import com.etop.weixin.entity.req.BaseReqEntity;
import com.etop.weixin.entity.req.event.*;
import com.etop.weixin.entity.req.msg.BaseMsgReq;
import com.etop.weixin.entity.req.msg.TextMsgReq;
import com.etop.weixin.entity.resp.Article;
import com.etop.weixin.service.MessageService;
import com.etop.weixin.utils.MessageUtil;
import com.etop.weixin.utils.MsgDedupUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * 微信请求处理服务类
 * Created by Jeremie on 2014/12/17.
 */
@Service("RequestService")
public class RequestService extends BaseService {
    @Autowired
    private AccountDAO accountDAO;
    @Autowired
    private MassDAO massDAO;
    @Autowired
    private AutoReplyDAO autoReplyDAO;
    @Autowired
    private MaterialTextDAO materialTextDAO;
    @Autowired
    private MaterialNewsDAO materialNewsDAO;
    @Autowired
    private MaterialMutinewsDAO materialMutinewsDAO;
    @Autowired
    private MaterialImageDAO materialImageDAO;
    @Autowired
    private MaterialVoiceDAO materialVoiceDAO;
    @Autowired
    private MaterialVideoDAO materialVideoDAO;
    @Autowired
    private WxUserManageService wxUserManageService;
    @Autowired
    private WeixinUserMessageDAO weixinUserMessageDAO;
    @Autowired
    private WxUserMessageService wxUserMessageService;
    @Autowired
    private WeixinMenuDAO weixinMenuDAO;

    private static String REGISTER_URL = "wxmanager/wxuser/register";

    /**
     * 根据微信id获取公众号token
     *
     * @param wechatId
     * @return
     */
    public String loadAccountToken(String wechatId) throws Exception {
        log.debug("******根据微信id获取公众号token******");
        Map<String, Object> params = new HashMap<>();
        params.put("wechatId", wechatId);
        Account account = accountDAO.findUniqueResult("from Account a where a.valid = 1 and a.wechatId = :wechatId", params);
        if (account != null)
            return account.getToken();
        else
            return null;
    }

    /**
     * 根据微信id获取公众号账户
     *
     * @param wechatId
     * @return
     */
    public Account loadAccount(String wechatId) throws Exception {
        log.debug("******根据微信id获取公众号账户******");
        Map<String, Object> params = new HashMap<>();
        params.put("wechatId", wechatId);
        Account account = accountDAO.findUniqueResult("from Account a where a.valid = 1 and a.wechatId = :wechatId", params);
        return account;
    }

    /**
     * 检验signature
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @param TOKEN
     * @return
     */
    public String verify(String signature, String timestamp, String nonce, String echostr, String TOKEN) throws Exception {
        log.debug("******检验signature******");
        List<String> list = new ArrayList<>(3);
        list.add(TOKEN);
        list.add(timestamp);
        list.add(nonce);
        Collections.sort(list);// 排序
        if ((new SimpleHash("SHA-1", list.get(0) + list.get(1) + list.get(2))).toString().equals(signature))
            return echostr;
        else
            return "";
    }

    /**
     * 处理微信请求
     *
     * @param xml
     * @param session
     * @return
     */
    public String handleMsg(String xml, HttpSession session, String wechatId, String contextPath, String url) throws Exception {
        log.debug("******处理微信请求******");
        BaseReqEntity baseReqEntity = MessageUtil.parseXml(xml);
        String result = "";
        try {
            if ("event".equals(baseReqEntity.getMsgType())) {
                if (!MsgDedupUtil.isRepetitive(baseReqEntity.getFromUserName(), baseReqEntity.getCreateTime()))
                    result = handleEvent(baseReqEntity, wechatId, contextPath, url);
            } else {
                /*
                Integer accountId = loadAccount(wechatId).getId();
                if (!wxUserManageService.isRegistered(accountId, baseReqEntity.getFromUserName())) {
                    //若用户没有填写真实姓名和联系号码，则直接返回
                    REGISTER_URL = url + REGISTER_URL;
                    return MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(),
                            "请先绑定你的个人信息 <a href=\"" + REGISTER_URL + "?openId=" + baseReqEntity.getFromUserName() +
                                    "&accountId=" + accountId.toString() + "\">点我绑定</a>");
                }
                */

                BaseMsgReq baseMsgReq = (BaseMsgReq) baseReqEntity;
                if (!MsgDedupUtil.isRepetitive(baseMsgReq.getMsgId())) {
                    //保存用户发送过来的消息
                    wxUserMessageService.saveWxMsg(baseReqEntity, loadAccount(wechatId).getId(), contextPath);
                    if (baseMsgReq.getMsgType().equals("text"))
                        result = handleCustomMsg((TextMsgReq) baseMsgReq, wechatId, contextPath, url);
                    if (StringUtils.isEmpty(result)) {
                        MessageHandler messageHandler = new MessageHandler() {
                            @Override
                            public String replyMessage(BaseReqEntity reqEntity, String wechatId) throws Exception {
                                return null;
                            }

                            @Override
                            public String replyMessageBySession(BaseReqEntity reqEntity, HttpSession session, String wechatId) throws Exception {
                                return null;
                            }
                        };
                        result = messageHandler.replyMessage(baseReqEntity, wechatId);
                        result = messageHandler.replyMessageBySession(baseReqEntity, session, wechatId);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //return StringUtils.isEmpty(result) && !repeat ? MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "服务信息错误，无法回复！") : result;
            return result;
        }
    }

    /**
     * 处理微信事件请求
     *
     * @param baseReqEntity
     * @param wechatId
     * @return
     */
    public String handleEvent(BaseReqEntity baseReqEntity, String wechatId, String contextPath, String url) throws Exception {
        BaseWeixinEvent baseWeixinEvent = (BaseWeixinEvent) baseReqEntity;
        Account account = loadAccount(wechatId);
        String result = "";
        switch (baseWeixinEvent.getEventType()) {
            case SUBSCRIBE:
                SubscribeEvent subscribeEvent = (SubscribeEvent) baseWeixinEvent;
                log.debug("******处理关注事件******");
                new Thread((Runnable) () -> wxUserManageService.saveOrUpdateWxUser(wechatId, baseReqEntity.getFromUserName())).start();
                //result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "欢迎关注" + account.getName() + "公众号");
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "请先绑定你的个人信息 <a href=\"" + REGISTER_URL + "\">点我绑定</a>");
                break;
            case UNSUBSCRIBE:
                SubscribeEvent unSubscribeEvent = (SubscribeEvent) baseWeixinEvent;
                log.debug("******处理取消关注事件******");
                new Thread((Runnable) () -> wxUserManageService.deleteWxUser(wechatId, baseReqEntity.getFromUserName())).start();
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "取消关注" + account.getName() + "公众号");
                break;
            case SUBSCRIBEBYQR:
                SubscribeByQREvent subscribeByQREvent = (SubscribeByQREvent) baseWeixinEvent;
                log.debug("******处理二维码关注事件******");
                new Thread((Runnable) () -> wxUserManageService.saveOrUpdateWxUser(wechatId, baseReqEntity.getFromUserName())).start();
                //result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "欢迎通过二维码关注" + account.getName() + "公众号");
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "请先绑定你的个人信息 <a href=\"" + REGISTER_URL + "\">点我绑定</a>");
                break;
            case SUBSCRIBEDBYQR:
                SubscribeByQREvent subscribedByQREvent = (SubscribeByQREvent) baseWeixinEvent;
                log.debug("******处理已经关注后再次进行的二维码关注事件******");
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "欢迎再次通过二维码关注" + account.getName() + "公众号");
                break;
            case LOCATION:
                LocationEvent locationEvent = (LocationEvent) baseWeixinEvent;
                log.debug("******处理上报地理位置事件******");
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), "你上报了你的地理位置：(" + locationEvent.getLatitude() + "," + locationEvent.getLatitude() + ")");
                break;
            case MENUVIEW:
                break;
            case MENUCLICK:
                MenuEvent event = (MenuEvent) baseWeixinEvent;
                log.debug("******处理菜单按钮事件******");
                result = this.handleClickMenu(event, wechatId, contextPath, url);
                break;
            case TEMPLATESENDJOBFINISH:
                break;
            case MASSSENDJOBFINISH:
                MassEndJobEvent massEndJobEvent = (MassEndJobEvent) baseWeixinEvent;
                log.debug("******接收群发完成事件,群发消息ID：" + massEndJobEvent.getMsgID() + "，更新群发消息******");
                Map<String, Object> map = this.createParamMap();
                map.put("msgId", massEndJobEvent.getMsgID());
                Mass mass = massDAO.findUniqueResult("from Mass m where m.msgId = :msgId and m.valid = 1", map);
                mass.setErrorCount(massEndJobEvent.getErrorCount());
                mass.setFilterCount(massEndJobEvent.getFilterCount());
                mass.setSentCount(massEndJobEvent.getSentCount());
                mass.setTotalCount(massEndJobEvent.getTotalCount());
                mass.setStatus(massEndJobEvent.getStatus());
                massDAO.save(mass);
                break;
            default:
                break;
        }
        return result;
    }

    /**
     * 处理微信消息请求
     *
     * @param textMsgReq
     * @param wechatId
     * @return
     */
    public String handleCustomMsg(TextMsgReq textMsgReq, String wechatId, String contextPath, String url) throws Exception {
        Account account = loadAccount(wechatId);
        //用数据库查询的方式获取最匹配的回复消息，没有则回复空串
        String queryString = "from AutoReply t where t.valid = 1 and t.account.id = :accountId and(" +
                "( t.keyType = 1 and  t.keyWord = '" + textMsgReq.getContent() + "') " +
                "or ( t.keyType = 2 and  t.keyWord like '" + textMsgReq.getContent() + "%')" +
                "or ( t.keyType = 3 and  t.keyWord like '%" + textMsgReq.getContent() + "')" +
                "or ( t.keyType = 4 and  t.keyWord like '%" + textMsgReq.getContent() + "%')" +
                ") order by t.keyType asc , t.orderId asc";
        Map<String, Object> map = this.createParamMap();
        map.put("accountId", account.getId());
        List<AutoReply> autoReplyList = autoReplyDAO.find(queryString, map);
        if (autoReplyList.isEmpty())
            return "";
        else {
            AutoReply autoReply = autoReplyList.get(0);
            return this.getMaterialResponse(autoReply.getMaterialType(), autoReply.getMaterialId()
                    , wechatId, contextPath, url, textMsgReq, autoReply.getContent());
        }
    }

    /**
     * 处理菜单按钮事件
     *
     * @param event
     * @return
     */
    public String handleClickMenu(MenuEvent event, String wechatId, String contextPath, String url) throws Exception {
        String queryString = "from WeixinMenu t where t.valid = 1 and t.menuType = :type and t.menuKey = :key";
        Map<String, Object> params = this.createParamMap();
        params.put("type", "click");
        params.put("key", event.getEventKey());
        //获取菜单项
        WeixinMenu weixinMenu = weixinMenuDAO.findUniqueResult(queryString, params);
        if (weixinMenu == null)
            return "";
        return this.getMaterialResponse(weixinMenu.getMaterialType(), weixinMenu.getMaterialId()
                , wechatId, contextPath, url, event, weixinMenu.getContent());
    }


    /**
     * 获取素材回复
     *
     * @param materialType  素材类型
     * @param materialId    素材id
     * @param wechatId      公众号id
     * @param contextPath   本地路径
     * @param url           url路径
     * @param baseReqEntity 基本请求实体
     * @param textContent   文本内容，不用的话可为空
     * @return
     * @throws Exception
     */
    public String getMaterialResponse(String materialType, Integer materialId, String wechatId, String contextPath,
                                      String url, BaseReqEntity baseReqEntity, String textContent) throws Exception {
        //获取素材
        String result = "";
        Account account = loadAccount(wechatId);
        //准备获取的HQL语句
        String materialQueryString = "from Material" + materialType + " t where t.valid = 1 and t.id = :id";
        Map<String, Object> materialMap = this.createParamMap();
        materialMap.put("id", materialId);
        switch (materialType) {
            //单图文消息回复
            case "News":
                log.debug("******回复单图文消息******");
                MaterialNews materialNews = materialNewsDAO.findUniqueResult(materialQueryString, materialMap);
                Article article = new Article();
                article.setTitle(materialNews.getTitle());
                article.setDescription(materialNews.getDescription());
                article.setPicUrl(url + "home/wxmanage/upload/" + account.getUser().getId() + "/image/" + materialNews.getThumbMedia().getUrl());
                article.setUrl(materialNews.getContentUrl());
                ArrayList<Article> articles = new ArrayList<>();
                articles.add(article);
                result = MessageService.getNewsMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), articles);
                break;
            //多图文消息回复
            case "Mutinews":
                log.debug("******回复多图文消息******");
                MaterialMutinews materialMutinews = materialMutinewsDAO.findUniqueResult(materialQueryString, materialMap);
                String[] materialNewsIds = materialMutinews.getMultIds().split(",");
                ArrayList<Article> mulArticles = new ArrayList<>();
                for (String materialNewsId : materialNewsIds) {
                    Map<String, Object> materialnewsMap = this.createParamMap();
                    materialnewsMap.put("materialNewsId", Integer.parseInt(materialNewsId));
                    MaterialNews materialnews = materialNewsDAO.findUniqueResult("from MaterialNews t where t.valid = 1 and t.id = :materialNewsId", materialnewsMap);
                    Article mulArticle = new Article();
                    mulArticle.setTitle(materialnews.getTitle());
                    mulArticle.setDescription(materialnews.getDescription());
                    mulArticle.setPicUrl(url + "home/wxmanage/upload/" + account.getUser().getId() + "/image/" + materialnews.getThumbMedia().getUrl());
                    mulArticle.setUrl(materialnews.getContentUrl());
                    mulArticles.add(mulArticle);
                }
                result = MessageService.getNewsMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), mulArticles);
                break;
            //文本消息内容回复
            case "Text":
                log.debug("******回复文本消息******");
                //MaterialText materialText = materialTextDAO.findUniqueResult(materialQueryString, materialMap);
                result = MessageService.getTextMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), textContent);
                break;
            //图片消息内容回复
            case "Image":
                log.debug("******回复图片消息******");
                MaterialImage materialImage = materialImageDAO.findUniqueResult(materialQueryString, materialMap);
                String localImageUrl = contextPath + "home/wxmanage/upload/" + account.getUser().getId() + "/image/" + materialImage.getUrl();
                result = MessageService.getImageMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(), WeixinTimeUtil.getImageMediaId(localImageUrl, materialImage));
                break;
            //音频消息内容回复
            case "Voice":
                log.debug("******回复音频消息******");
                MaterialVoice materialVoice = materialVoiceDAO.findUniqueResult(materialQueryString, materialMap);
                String localVoiceUrl = url + "home/wxmanage/upload/" + account.getUser().getId() + "/voice/" + materialVoice.getUrl();
                String localHqVoiceUrl;
                if(!StringUtils.isEmpty(materialVoice.getHqUrl()))
                    localHqVoiceUrl = url + "home/wxmanage/upload/" + account.getUser().getId() + "/voice/" + materialVoice.getHqUrl();
                else
                    localHqVoiceUrl = url + "home/wxmanage/upload/" + account.getUser().getId() + "/voice/" + materialVoice.getUrl();
                String localThumbImageUrl = contextPath + "home/wxmanage/upload/";
                localThumbImageUrl += account.getUser().getId();
                localThumbImageUrl += "/image/" + materialVoice.getThumbMedia().getUrl();
                result = MessageService.getMusicMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(),
                        materialVoice.getTitle(), materialVoice.getDescription(), localVoiceUrl, localHqVoiceUrl,
                        WeixinTimeUtil.getThumbImageMediaId(localThumbImageUrl, materialVoice.getThumbMedia()));
                break;
            //视频消息内容回复
            case "Video":
                log.debug("******回复视频消息******");
                MaterialVideo materialVideo = materialVideoDAO.findUniqueResult(materialQueryString, materialMap);
                String localVideoUrl = contextPath + "home/wxmanage/upload/" + account.getUser().getId() + "/video/" + materialVideo.getUrl();
                result = MessageService.getVideoMsg(baseReqEntity.getFromUserName(), baseReqEntity.getToUserName(),
                        WeixinTimeUtil.getVideoMediaId(localVideoUrl, materialVideo),
                        materialVideo.getTitle(), materialVideo.getDescription());
                break;
            default:
                break;
        }
        return result;
    }
}
